package com.xiang.ad.index;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.PriorityOrdered;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Created by xiang.
 * 实现一个索引的缓存（记录），易于简单地去获取索引服务___实现了对索引类的统计和缓存。
 * DataTable作为所有index服务的缓存的java bean
 * 需要在缓存出现之前就已经存在，因为要拿这个table保存所有的index，记录所有的缓存服务
 */
@Component //
public class DataTable implements ApplicationContextAware, PriorityOrdered {
    //ApplicationContextAware：xxxAware就是想要使用到xxx，这里就是想要使用到ApplicationContextAware
    //                        想要得到当前系统中spring已经初始化的各个bean或者组件
    //PriorityOrdered:优先级排序，spring容器在初始化的时候，会初始化我们在应用中定义的所有的bean（component、contoller、service、、）
    //                可以定义一些初始化的顺序，使用了PriorityOrdered时候，
    //                spring容器会事先把这一类排好序的bean完成初始化，再去初始化其他的。

    //引入上下文
    private static ApplicationContext applicationContext;

    //保存所有的index服务，key是索引的索引类型，value是具体的索引服务实例
    public static final Map<Class, Object> dataTableMap = new ConcurrentHashMap<>();

    //初始化上下文
    @Override
    public void setApplicationContext(
            ApplicationContext applicationContext) throws BeansException {
        // applicationContext 是 ApplicationContextAware提供的
        DataTable.applicationContext = applicationContext;
    }

    //定义初始化顺序
    @Override
    public int getOrder() {
        return PriorityOrdered.HIGHEST_PRECEDENCE;//给予最高的优先级（越小优先级越高，这里是int类型的最小值）
    }

    //获取缓存（存储）的方法  提供给想要使用索引服务的服务类，获取到对应的索引服务
    //dataTableMap 的作用并不是用来缓存对象，而是用来方便的查找 Spring 已经装载的对象。
    //使用 ApplicationContext 的 getBean 方法肯定是可以的，这里的主要目的还是想去自己对这些 Bean 做管理。
    //如果不放map，那么就要新建n多个getxx方法了
    //**使用方法** DataTable.of(CreativeUnitIndex.class)  获取xxIndex的索引服务
    @SuppressWarnings("all")
    public static <T> T of(Class<T> clazz) {//给出对应的索引服务类型
        //尝试通过 map.get(bean的类型) 获取bean实例
        T instance = (T) dataTableMap.get(clazz);
        if (null != instance) {//如果不存在（可能是首次获取，bean还没有添加到table中）
            return instance;
        }
        //table中添加索引服务（首先获取）
        dataTableMap.put(clazz, bean(clazz));//bean方法通过java类的类型获取到对应的bean
        return (T) dataTableMap.get(clazz);
    }

    //通过beanName获取到容器中的bean（这个暂时还没有用到）
    @SuppressWarnings("all")
    private static <T> T bean(String beanName) {
        return (T) applicationContext.getBean(beanName);
    }

    //通过java类的类型获取容器中的bean
    @SuppressWarnings("all")
    private static <T> T bean(Class clazz) {
        return (T) applicationContext.getBean(clazz);
    }
}
